package com.ruoyi.warning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.warning.domain.entity.*;
import com.ruoyi.warning.domain.query.DeviceQuery;
import com.ruoyi.warning.domain.query.PropertyQuery;
import com.ruoyi.warning.domain.vo.DeviceVO;
import com.ruoyi.warning.domain.vo.PropertyVO;
import com.ruoyi.warning.mapper.DevicesMapper;
import com.ruoyi.warning.mapper.LinksMapper;
import com.ruoyi.warning.mapper.PropertyMapper;
import com.ruoyi.warning.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author chenhc
 * @since 2025-03-26
 */
@Service
public class DevicesServiceImpl extends ServiceImpl<DevicesMapper, Device> implements IDevicesService {
@Resource
private IEventService eventService;
    @Resource
    private DevicesMapper devicesMapper;
    @Resource
    private IPropertyService iPropertyService;
    @Resource
    private IPortsService iPortsService;
    @Resource
    private IDrawingBoardDevicexyService iDrawingBoardDevicexyService;
    @Resource
    private LinksMapper linksMapper;
    @Resource
    private IThresholdService thresholdService;
    @Resource
    private PropertyMapper propertyMapper;
    @Resource
    private IDevicesPingService devicesPingService;
    @Resource
    private IMempoolsService mempoolsService;

    @Override
    public Object getAllDevices(DeviceQuery query) {
        List<DeviceVO> list = devicesMapper.getAllDevicesPage(query);
        return list;
    }

    @Override
    public Object getDeviceDetail(String deviceId) {
        DeviceVO deviceVO = new DeviceVO();
        Device device = this.getById(deviceId);
        LambdaQueryWrapper<Property> wrapper = new QueryWrapper<Property>().lambda()
                .eq(Property::getHostname, device.getHostname());
        Property property = iPropertyService.getOne(wrapper);
        if(ObjectUtils.isNotEmpty(property)){
            BeanUtils.copyProperties(property,deviceVO);
            if((ObjectUtils.isNotEmpty(property.getStatus())&&property.getStatus()==1)||device.getStatus()==1){
                deviceVO.setStatus(1);
            }else {
                deviceVO.setStatus(0);
            }
        }
        BeanUtils.copyProperties(device,deviceVO);
        PropertyQuery query = new PropertyQuery();
        query.setHostname(device.getHostname());
        List<PropertyVO> propertyList = propertyMapper.getList(query);
        if(ObjectUtils.isEmpty(deviceVO.getManualType())){
            deviceVO.setManualType(deviceVO.getType());
        }
        if(ObjectUtils.isNotEmpty(propertyList)){
            deviceVO.setSerialWrong(propertyList.get(0).getSerialWrong());
        }
        return deviceVO;
    }

    @Override
    public Object getDeviceNet(String deviceId) throws IOException {
        DeviceVO deviceVO = new DeviceVO();
        Device device = this.getById(deviceId);
        InetAddress address = InetAddress.getByName(device.getHostname());
        //检测ping
        if(address.isReachable(3000)){
            deviceVO.setLastPingStatus("正常");
        }else{
            deviceVO.setLastPingStatus("异常");
        }
        if(device.getSnmpDisable()==0){
            //检测snmp
            try {
                // 构建命令数组（避免空格分割问题）
                String[] cmd = {"nc", "-u", "-z", "-v", device.getHostname(), "161"};
                // 创建进程
                Process process = Runtime.getRuntime().exec(cmd);
                // 读取标准输出
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println("++++++++++++++++++++");
                    System.out.println(line);
                    deviceVO.setTag1(line);
                }
                // 读取错误输出
                BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                while ((line = errorReader.readLine()) != null) {
                    System.out.println("=====================");
                    System.err.println(line);
                    deviceVO.setTag1(line);
                }
                if(ObjectUtils.isNotEmpty(deviceVO.getTag1())&&deviceVO.getTag1().contains("succeeded")){
                    deviceVO.setSnmpStatus("正常");
                }else {
                    deviceVO.setSnmpStatus("异常");
                }
                // 等待进程结束并获取退出码
                int exitCode = process.waitFor();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return deviceVO;
    }

    @Override
    public void deleteDevice(String id) {
        iPortsService.remove(new LambdaQueryWrapper<Port>()
                .eq(Port::getDeviceId, id));
        iDrawingBoardDevicexyService.remove(new LambdaQueryWrapper<DrawingBoardDevicexy>()
               .eq(DrawingBoardDevicexy::getDeviceId, id));
        linksMapper.removeLinkByDeviceId(id);
        thresholdService.remove(new LambdaQueryWrapper<Threshold>()
               .eq(Threshold::getDeviceId, id));
    }

    @Override
    public Object wirelessPage(DeviceQuery deviceQuery) {
        Page<Device> page = PageHelper.startPage(deviceQuery.getPageNum(),deviceQuery.getPageSize());
        List<Device> list = this.list(new LambdaQueryWrapper<Device>().eq(Device::getType,"wireless"));
        TableDataInfo tableDataInfo = new TableDataInfo(list, page.getTotal());
        return tableDataInfo;

    }

    @Override
    public Object updateDetail(Device device) {
        this.updateById(device);
        return null;
    }

    @Override
    public Object getAllDevicesPage(DeviceQuery query) {
        Long userId = SecurityUtils.getUserId();
        List<String> roleDevice = devicesMapper.getRoleDevice(userId);
        if(roleDevice.size()>0){
            query.setDeviceList(roleDevice);
        }
        Page<Device> page = PageHelper.startPage(query.getPageNum(),query.getPageSize());
        List<DeviceVO> list = devicesMapper.getAllDevicesPage(query);
        TableDataInfo tableDataInfo = new TableDataInfo(list, page.getTotal());
        return tableDataInfo;
    }

    @Override
    public Object resetXY(List<String> list) {
        LambdaUpdateWrapper<Device> wrapper = new UpdateWrapper<Device>().lambda()
                .in(Device::getDeviceId,list);
        return this.update(wrapper);
    }

    @Override
    public Object getDeviceWarningCount(String deviceId) {
        // 获取当前日期
        java.time.LocalDateTime now = java.time.LocalDateTime.now();
//        java.time.LocalDateTime todayEnd = now.atTime(23, 59, 59);
//        java.time.LocalDateTime todayStart = now.atStartOfDay();

        // 计算24小时前的时间
        java.time.LocalDateTime twentyFourHoursAgo = now.minusHours(24);
        LambdaQueryWrapper<Event> wrapperAll = new QueryWrapper<Event>().lambda()
                .eq(Event::getDeviceId,deviceId)
                ;
        LambdaQueryWrapper<Event> wrapperDay = new QueryWrapper<Event>().lambda()
                .eq(Event::getDeviceId,deviceId)
                .le(Event::getUpdateTime, now)
                .ge(Event::getUpdateTime, twentyFourHoursAgo)
                ;
        HashMap<String,Long> map = new HashMap<>();
        map.put("today",eventService.count(wrapperDay));
        map.put("all",eventService.count(wrapperAll));
        return map;
    }

    @Override
    public Object getDevicePING(String deviceId) throws IOException {
        DeviceVO deviceVO = new DeviceVO();
        Device device = this.getById(deviceId);
        InetAddress address = InetAddress.getByName(device.getHostname());
        //检测ping
        if(address.isReachable(3000)){
            deviceVO.setLastPingStatus("正常");
        }else{
            deviceVO.setLastPingStatus("异常");
        }
        return deviceVO;
    }

    @Override
    public Object getDeviceSNMP(String deviceId) {
        DeviceVO deviceVO = new DeviceVO();
        Device device = this.getById(deviceId);
        if(device.getSnmpDisable()==0){
            //检测snmp
            try {
                // 构建命令数组（避免空格分割问题）
                String[] cmd = {"nc", "-u", "-z", "-v", device.getHostname(), "161"};
                // 创建进程
                Process process = Runtime.getRuntime().exec(cmd);
                // 读取标准输出
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println("++++++++++++++++++++");
                    System.out.println(line);
                    deviceVO.setTag1(line);
                }
                // 读取错误输出
                BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                while ((line = errorReader.readLine()) != null) {
                    System.out.println("=====================");
                    System.err.println(line);
                    deviceVO.setTag1(line);
                }
                if(ObjectUtils.isNotEmpty(deviceVO.getTag1())&&deviceVO.getTag1().contains("succeeded")){
                    deviceVO.setSnmpStatus("正常");
                }else {
                    deviceVO.setSnmpStatus("异常");
                }
                // 等待进程结束并获取退出码
                int exitCode = process.waitFor();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return deviceVO;
    }

    @Override
    public Object addDevice(Integer deviceId) {
        Threshold threshold1 = new Threshold();
        threshold1.setDeviceId(deviceId);
        threshold1.setType("CPU利用率");
        Threshold threshold2 = new Threshold();
        threshold2.setDeviceId(deviceId);
        threshold2.setType("内存利用率");
        Threshold threshold3 = new Threshold();
        threshold3.setDeviceId(deviceId);
        threshold3.setType("温度");
        List<Threshold> list = new ArrayList<>();
        list.add(threshold1);
        list.add(threshold2);
        list.add(threshold3);
        thresholdService.saveBatch(list);
        return null;
    }

    @Override
    public void refresh() {
        //找到所有开启了snmp的离线设备
        List<Device> list = this.list(new LambdaQueryWrapper<Device>()
                .eq(Device::getSnmpDisable,0)
                .eq(Device::getStatus,0));
        List<String> hostnameList = new ArrayList<>();
        for(Device device:list){
            //检测snmp
            try {
                // 构建命令数组（避免空格分割问题）
                String[] cmd = {"nc", "-u", "-z", "-v", device.getHostname(), "161"};
                // 创建进程
                Process process = Runtime.getRuntime().exec(cmd);
                // 读取标准输出
                BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println("++++++++++++++++++++");
                    System.out.println(line);
                    device.setTag1(line);
                }
                // 读取错误输出
                BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                while ((line = errorReader.readLine()) != null) {
                    System.out.println("=====================");
                    System.err.println(line);
                    device.setTag1(line);
                }
                if(ObjectUtils.isNotEmpty(device.getTag1())&&device.getTag1().contains("succeeded")){
                    //snmp状态正常
                    hostnameList.add(device.getHostname());
                }
                // 等待进程结束并获取退出码
                int exitCode = process.waitFor();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //不为空才更新
        if(ObjectUtils.isNotEmpty(hostnameList)){
            List<Property> propertyListAll = iPropertyService.list(new LambdaQueryWrapper<Property>()
                    .eq(Property::getStatus,1));
            for(Property property:propertyListAll){
                if(hostnameList.contains(property.getHostname())){
                    property.setStatus(1);
                }else {
                    property.setStatus(null);
                }
            }
            iPropertyService.updateBatchById(propertyListAll);
        }
    }

    @Override
    public void savePing() {
//        List<Property> propertyList = iPropertyService.list(new LambdaQueryWrapper<Property>()
//                .eq(Property::getDeviceType,"服务器"));
        List<Property> propertyList = iPropertyService.list();
        List<String> hostnameList = propertyList.stream()
                .map(Property::getHostname)
                .collect(Collectors.toList());
        //记录设备的ping延迟
        List<Device> deviceList = this.list(new LambdaQueryWrapper<Device>()
                .eq(Device::getPingMonitor,1)
                .in(Device::getHostname,hostnameList));
        List<DevicesPing> devicesPingList = new ArrayList<>();
        Date date = new Date();
        LocalDateTime localDateTime = date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        for(Device device:deviceList){
            DevicesPing devicesPing = new DevicesPing();
            devicesPing.setDeviceId(device.getDeviceId());
            devicesPing.setPing(device.getLastPingTimetaken());
            devicesPing.setInserted(localDateTime);
            devicesPingList.add(devicesPing);
        }
        devicesPingService.saveOrUpdateBatchByMultiId(devicesPingList);
    }

    @Override
    public Object getDeviceMempoolChart(DeviceQuery deviceQuery) {
        //获取设备
        Device device = this.getById(deviceQuery.getDeviceId());
        if(ObjectUtils.isEmpty(device)){
            return null;
        }
        //找到物理内存
        Mempool mempool = mempoolsService.getOne(new LambdaQueryWrapper<Mempool>()
                .eq(Mempool::getDeviceId,deviceQuery.getDeviceId())
                .eq(Mempool::getMempoolDescr,"Physical memory"));
        if(ObjectUtils.isEmpty(mempool)){
            return null;
        }
        //拼接命令
        String command = "rrdtool fetch /home/fengli/librenms-master/examples/compose/librenms/rrd/"
                +device.getHostname()+"/mempool-hrstorage-system-"+mempool.getMempoolIndex()+
                ".rrd AVERAGE --start now-"+deviceQuery.getTimeInterval()+" --end now";
//        String command = "rrdtool fetch /home/fengli/librenms-master/examples/compose/librenms/rrd/"
//                +device.getHostname()+"/mempool-hrstorage-system-"+mempool.getMempoolIndex()+
//                ".rrd AVERAGE --start now-"+deviceQuery.getTimeInterval()+" --end now";
        System.out.println( command);
        Map<String, Long> map = new HashMap<>();
        try {
            // 执行命令
            Process process = Runtime.getRuntime().exec(command);
            int exitCode = process.waitFor();
            // 如果命令执行失败，返回空
            if (exitCode != 0) {
                System.out.println("命令执行失败，返回码为：" + exitCode);
                return null;
            }
            // 处理正常返回结果
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            formatter.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
            while ((line = reader.readLine()) != null) {
                String[] parts = line.split(":");
                if (parts.length >= 2) {
                    try {
                        String timestamp = formatter.format(new Date(Long.valueOf(parts[0])*1000));
                        Long value = utilization(parts[1]);
                        System.out.println("Timestamp: " + timestamp);
                        System.out.println("Value: " + value);
                        map.put(timestamp, value);
                    }catch (NumberFormatException e) {
                        System.out.println("数据格式错误，跳过该行: " + line);
                    } catch (IllegalArgumentException e) {
                        System.out.println("计算利用率出错，跳过该行: " + line);
                    }
                }
            }
            System.out.println( map);
        }
        catch (Exception e) {
            System.out.println("发生异常：" + e.getMessage());
            // 如果发生异常，返回空
            return null;
        }
        Map<String, Long> sortedMap = new TreeMap<>(map);
        return sortedMap;
    }

    @Override
    public Object getDeviceProcessorChart(DeviceQuery deviceQuery) {
        //获取设备
        Device device = this.getById(deviceQuery.getDeviceId());
        if(ObjectUtils.isEmpty(device)){
            return null;
        }
        //拼接命令
        String[] command = {
                "/bin/bash",
                "-c", "for file in /home/fengli/librenms-master/examples/compose/librenms/rrd/"
                +device.getHostname()+"/processor-hr-*.rrd; do echo ; rrdtool fetch \"$file\" AVERAGE --start now-"
                +deviceQuery.getTimeInterval()+" --end now;done"};
//        String command = "for file in /home/fengli/librenms-master/examples/compose/librenms/rrd/"
//                +device.getHostname()+"/processor-hr*.rrd; do echo ; rrdtool fetch \"$file\" AVERAGE --start "
//                +deviceQuery.getStartTime()+" --end "+deviceQuery.getEndTime()+";done";
        Map<Long,  List<Double>> timeValuesMap = new HashMap<>();
        System.out.println( command);
        try {
            // 执行命令
            Process process = Runtime.getRuntime().exec(command);
            int exitCode = process.waitFor();
            // 如果命令执行失败，返回空
            if (exitCode != 0) {
                return null;
            }
            // 处理正常返回结果
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            formatter.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
            while ((line = reader.readLine()) != null) {
                String[] parts = line.split(":");
                if (parts.length >= 2) {
                    try {
                        String str = parts[1].trim();
                        // 过滤掉NaN值
                        if ("-nan".equals(str)) {
                            continue;
                        }
                        Double value = Double.parseDouble(str);
                        Long timestamp = Long.parseLong(parts[0].trim())*1000;
                        timeValuesMap.computeIfAbsent(timestamp, k -> new ArrayList<>()).add(value);
                        System.out.println("Timestamp: " + timestamp*1000);
                        System.out.println("Value: " + value);
                    }catch (NumberFormatException e) {
                        System.out.println("数据格式错误，跳过该行: " + line);
                    } catch (IllegalArgumentException e) {
                        System.out.println("计算利用率出错，跳过该行: " + line);
                    }
                }
            }
        } catch (Exception e) {
            System.out.println("发生异常：" + e.getMessage());
            // 如果发生异常，返回空
            return null;
        }
        Map<String, Integer> result = new HashMap<>();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        formatter.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        for (Map.Entry<Long, List<Double>> entry : timeValuesMap.entrySet()) {
            Long timestamp = entry.getKey();
            List<Double> values = entry.getValue();
            double average = values.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
            int value  = (int) Math.round(average);
            result.put(formatter.format(new Date(timestamp)), value);
        }
        Map<String, Integer> sortedMap = new TreeMap<>(result);
        return sortedMap;
    }

    private Long utilization(String all) {
        all = all.trim();
        if (all == null || all.isEmpty()||
                "-nan".equals( all)||"-nan -nan".equals(all)) {
            return null;
        }
        String[] sz = all.split(" ");
        double used = Double.parseDouble(sz[0]);
        double unused = Double.parseDouble(sz[1]);
        if (used < 0 || unused < 0) {
            throw new IllegalArgumentException("使用量不能为负数");
        }
        double total = used + unused;
        if (total <= 0) {
            throw new IllegalArgumentException("总量不能为零或负数");
        }
        // 计算利用率并四舍五入保留两位小数
        double utilization = (used / total) * 100;
        return Math.round(utilization);
    }


    @Override
    public List<DevicesPing> getPing(DeviceQuery deviceQuery) {
        List<DevicesPing> list = devicesPingService.list(new LambdaQueryWrapper<DevicesPing>()
                .eq(DevicesPing::getDeviceId,deviceQuery.getDeviceId())
                .ge(DevicesPing::getInserted,deviceQuery.getStartTime())
                .le(DevicesPing::getInserted,deviceQuery.getEndTime())
                .orderByDesc(DevicesPing::getInserted));
        return list;
    }

    public static void main(String[] args) {
        String u = "3.5257585546e+09";
        String free = "7.6816016539e+08";
        double used = Double.parseDouble(u);
        double unused = Double.parseDouble(free);
        if (used < 0 || unused < 0) {
            throw new IllegalArgumentException("使用量不能为负数");
        }
        double total = used + unused;
        if (total <= 0) {
            throw new IllegalArgumentException("总量不能为零或负数");
        }
        // 计算利用率并四舍五入保留两位小数
        double utilization = (used / total) * 100;
        System.out.println( utilization);

        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        formatter.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        String timestamp = formatter.format(new Date(Long.valueOf(1761899700)*1000));
        System.out.println( timestamp);
    }
}
